﻿using G711;
using Gimela.Net.Rtp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using G722;
using Sinrey.SoundCard;

namespace RtpSend
{
    public partial class Form1 : Form
    {
        private class ThreadParam
        {
            public string protocal;
            public string filename;
            public int samplerate;
            public int channel;
            public string dstip;
            public int dstport;
        }
        private delegate void WorkProcessHandler(string info, bool completed, int param);

        private Thread RtpFileThreadHandle;
        private Thread RtpSoundCardThreadHandle;
        public Form1()
        {
            InitializeComponent();

            string exename = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
            string path = System.IO.Path.GetFullPath(exename);
            string txtfile = path + "\readme.txt";
            //FileStream fs = File.OpenRead(txtfile);
            //fs.readline
            if (System.IO.File.Exists(txtfile))
            {
                StreamReader sr = new StreamReader(txtfile);
                string lines = sr.ReadToEnd();
                textBox3.Text = lines;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "wav file|*.wav";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox4.Text = openFileDialog1.FileName;
            }
        }


        private void button2_Click(object sender, EventArgs e)
        {
            if (false == File.Exists(textBox4.Text))
            {
                MessageBox.Show("audio file is not exist.");
                return;
            }
            FileStream fs = File.OpenRead(textBox4.Text);
            byte[] dat = new byte[1024];
            int datlen = fs.Read(dat, 0, 44);
            if (datlen == 44)
            {
                int formattag = 256 * dat[21] + dat[20];
                int channel = 256 * dat[23] + dat[22];
                int samplespersec = 0x1000000 * dat[27] + 0x10000 * dat[26] + 0x100 * dat[25] + dat[24];
                int bits = 0x100 * dat[35] + dat[34];

                if ((formattag != 0x0001) || (channel != 1) || (samplespersec != 16000) || (bits != 16))
                {
                    MessageBox.Show("Unsupported file format.");
                    return;
                }

                ThreadParam ap = new ThreadParam();
                ap.filename = textBox4.Text;
                ap.samplerate = samplespersec;
                ap.channel = channel;
                ap.protocal = comboBox1.Text;
                ap.dstip = textBox2.Text;
                ap.dstport = Convert.ToInt32(textBox3.Text);

                RtpFileThreadHandle = new Thread(RtpFileThread);
                RtpFileThreadHandle.IsBackground = true;
                RtpFileThreadHandle.Start(ap);
            }
            fs.Close();
        }

        private void RtpFileThreadProcess(string info, bool completed, int param)
        {
            progressBar1.Value = param;
            if (completed)
            {
                progressBar1.Value = 0;
            }
            //Application.DoEvents();
        }
        private void RtpFileThread(object obj)
        {
            int protocal=0;
            int sequenceNumber = 0;
            long timestamp = 0;
            ThreadParam ap = (ThreadParam)obj;

            WorkProcessHandler h = new WorkProcessHandler(RtpFileThreadProcess);

            if (ap.protocal.Equals("G711U")) protocal = 0;
            else if (ap.protocal.Equals("G711A")) protocal = 8;
            else if (ap.protocal.Equals("G722")) protocal = 9;

            UdpClient udp = new UdpClient();
            IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);

            FileStream fs = File.OpenRead(ap.filename);
            if (fs != null)
            {
                
                byte[] dat = new byte[640];
                fs.Read(dat, 0, 44);
                int starttime = System.Environment.TickCount;
                int sendpacktime = 0;
                int sendbytes = 0;
                g722_encoder enc = new g722_encoder();
                g722.g722_reset_encoder(ref enc);
                while (true)
                {
                    if ((System.Environment.TickCount - starttime) >= sendpacktime)
                    {
                        int datlen;
                        datlen = fs.Read(dat, 0, 640);
                        sendpacktime += 20;
                        if (protocal != 9)
                        {
                            short[] pcm = new short[160];
                            byte[] dat711 = new byte[320];
                            for (int i = 0; i < 160; i++)
                            {
                                dat711[2 * i + 0] = dat[4 * i + 0];
                                dat711[2 * i + 1] = dat[4 * i + 1];
                            }
                            IntPtr p = Marshal.UnsafeAddrOfPinnedArrayElement(dat711, 0);
                            Marshal.Copy(p, pcm, 0, 160);

                            byte[] ba;
                            RtpPacket packet;
                            if (protocal == 0)
                            {
                                ba = g711.g711Encode_ulwa(pcm);
                                packet = new RtpPacket(RtpPayloadType.G711_uLaw, sequenceNumber, timestamp, ba, ba.Length);
                            }
                            else
                            {
                                ba = g711.g711Encode_alwa(pcm);
                                packet = new RtpPacket(RtpPayloadType.G711_aLaw, sequenceNumber, timestamp, ba, ba.Length);
                            }


                            sequenceNumber++;
                            timestamp += 20;// ba.Length;
                            //playfiletime += 20;
                            udp.Send(packet.ToArray(), packet.Length, ap.dstip, ap.dstport);
                        }
                        else//g722 
                        {
                            short[] pcm = new short[320];
                            IntPtr datptr = Marshal.UnsafeAddrOfPinnedArrayElement(dat, 0);
                            Marshal.Copy(datptr, pcm, 0, pcm.Length);
                            byte[] ba = g722.g722_encode(pcm, ref enc);
                            RtpPacket packet;
                            packet = new RtpPacket(RtpPayloadType.G722, sequenceNumber, timestamp, ba, ba.Length);
                            sequenceNumber++;
                            timestamp += 20;// ba.Length;
                            udp.Send(packet.ToArray(), packet.Length, ap.dstip, ap.dstport);
                        }

                        sendbytes += datlen;
                        if (datlen < 640) break;

                        this.BeginInvoke(h, ap.filename, false, (int)(sendbytes * 100 / fs.Length));
                    }
                }
            }
            fs.Close();
            udp.Close();

            this.BeginInvoke(h, ap.filename, true, 0);
        }

        private void RtpSoundCardThreadProcess(string info, bool completed, int param)
        {
            progressBar2.Value = param;
            if (completed)
            {
                progressBar2.Value = 0;
            }
            //Application.DoEvents();
        }

        double dbBase;
        private void RtpSoundCardThread(object obj)
        {
            double p = 0;
            double a = 0;
            for (int i = 0; i < 1024; i++)
            {
                a = 32768 * Math.Sin(i * 2 * 3.14159 / 1024);
                p += a * a;
            }

            dbBase = p / 1024;

            int protocal = 0;
            int sequenceNumber = 0;
            long timestamp = 0;
            ThreadParam ap = (ThreadParam)obj;

            WorkProcessHandler h = new WorkProcessHandler(RtpSoundCardThreadProcess);

            if (ap.protocal.Equals("G711U")) protocal = 0;
            else if (ap.protocal.Equals("G711A")) protocal = 8;
            else if (ap.protocal.Equals("G722")) protocal = 9;

            UdpClient udp = new UdpClient();
            IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);

            int ret = SoundCardDLL.SoundCardInit(16000);
            if (ret != 0) return;

            //-if (ret == 0)//successfully
            try
            {
                g722_encoder enc = new g722_encoder();
                g722.g722_reset_encoder(ref enc);
                while (true)
                {
                    if (SoundCardDLL.SoundCardWaitForInputData())
                    {
                        //if ((System.Environment.TickCount - starttime) >= sendpacktime)
                        //{
                        int datlen;
                        short[] dat = SoundCardDLL.SoundCardReadFrom(320);
                        if (dat == null) continue;
                        //sendpacktime += 20;
                        if (protocal != 9)
                        {
                            short[] pcm = new short[160];
                            for (int i = 0; i < 160; i++) pcm[i] = dat[2 * i];

                            byte[] ba;
                            RtpPacket packet;
                            if (protocal == 0)
                            {
                                ba = g711.g711Encode_ulwa(pcm);
                                packet = new RtpPacket(RtpPayloadType.G711_uLaw, sequenceNumber, timestamp, ba, ba.Length);
                            }
                            else
                            {
                                ba = g711.g711Encode_alwa(pcm);
                                packet = new RtpPacket(RtpPayloadType.G711_aLaw, sequenceNumber, timestamp, ba, ba.Length);
                            }


                            sequenceNumber++;
                            timestamp += 20;// ba.Length;
                            udp.Send(packet.ToArray(), packet.Length, ap.dstip, ap.dstport);
                        }
                        else//g722 
                        {
                            //short[] pcm = new short[320];
                            //IntPtr datptr = Marshal.UnsafeAddrOfPinnedArrayElement(dat, 0);
                            //Marshal.Copy(datptr, pcm, 0, pcm.Length);
                            byte[] ba = g722.g722_encode(dat, ref enc);
                            RtpPacket packet;
                            packet = new RtpPacket(RtpPayloadType.G722, sequenceNumber, timestamp, ba, ba.Length);
                            sequenceNumber++;
                            timestamp += 20;// ba.Length;
                            udp.Send(packet.ToArray(), packet.Length, ap.dstip, ap.dstport);
                        }

                        //sendbytes += datlen;
                        //if (datlen < 640) break;

                        //this.BeginInvoke(h, ap.filename, false, (int)(sendbytes * 100 / fs.Length));
                        //}
                        double mic_db = 0;
                        a = 0;
                        for (int i = 0; i < dat.Length; i++)
                        {
                            a += dat[i] * dat[i];
                        }
                        mic_db = 20 * Math.Log10(a / (dbBase * dat.Length));
                        mic_db += 100;
                        if (mic_db < 0) mic_db = 0;
                        if (mic_db > 100) mic_db = 100;

                        this.Invoke(h, "", false, Convert.ToInt32(mic_db));
                    }
                }
            }
            //catch (ThreadAbortException abortException)
            //{ 
            //    
            //}
            finally
            {
                this.Invoke(h, "", true, Convert.ToInt32(0));
                udp.Close();
                SoundCardDLL.SoundCardClose();
                RtpSoundCardThreadHandle = null;
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            /*
            g722_encoder enc = new g722_encoder() ;
            g722.g722_reset_encoder(ref enc);

            short[] incode = new short[320];

            for (int i = 0; i < incode.Length; i++) incode[i] = (short)i;

            byte[] code = g722.g722_encode(incode, ref enc);
            */
            if (RtpSoundCardThreadHandle == null)
            {
                ThreadParam ap = new ThreadParam();
                ap.protocal = comboBox2.Text;
                ap.dstip = textBox6.Text;
                ap.dstport = Convert.ToInt32(textBox5.Text);
                RtpSoundCardThreadHandle = new Thread(RtpSoundCardThread);
                RtpSoundCardThreadHandle.IsBackground = true;
                RtpSoundCardThreadHandle.Start(ap);

                button3.Text = "Stop";
                button3.BackColor = Color.Green;
            }
            else
            {
                RtpSoundCardThreadHandle.Abort();
                button3.Text = "Start";
                button3.BackColor = Color.Transparent;
            }

        }
        
        
    }
}
